﻿using System;
using HPSocketCS;
using BingoCommonConfig.Log4netConfig;
using BingoServerCommon.Common;
using System.Threading;

namespace BingoGameServerConsole
{
	class GameTcpServer
    {
        public  TcpPackServer Server = new TcpPackServer();
        public static GameTcpServer Instance;
        public GameTcpServer()
        {
            Instance = this;
        }

        public void Start(ushort port)
        {
            try
            {
                #region 设置服务器事件

                //连接到达事件
                Server.OnAccept += new TcpServerEvent.OnAcceptEventHandler(OnAccept);
                //数据到达事件
                Server.OnReceive += new TcpServerEvent.OnReceiveEventHandler(OnReceive);
                //连接关闭事件
                Server.OnClose += new TcpServerEvent.OnCloseEventHandler(OnClose);
                //服务器关闭事件
                Server.OnShutdown += new TcpServerEvent.OnShutdownEventHandler(OnShutdown);

                #endregion

                // 设置包头标识,与对端设置保证一致性
                Server.PackHeaderFlag = 0xa3;
                // 设置最大封包大小
                Server.MaxPackSize = 0x256;  //byte  

                Server.IpAddress = "0.0.0.0";
                Server.Port = port;
                // 启动服务
                Server.Start();

            }
            catch (Exception e)
            {
                Console.WriteLine("BingoTcpPackServer.Start() 异常");

                LogHelper.WriteFatal( e);
            }
        }
        /// <summary>
		/// 连接到达事件
		/// </summary>
		/// <param name="connId"></param>
		/// <param name="pClient"></param>
		/// <returns></returns>
		HandleResult OnAccept(IntPtr connId, IntPtr pClient)
        {

            try
            {
                // 获取客户端ip和端口
                string ip = string.Empty;
                ushort port = 0;
                if (Server.GetRemoteAddress(connId, ref ip, ref port))
                {
                    Console.WriteLine($" > [{connId},OnAccept] -> PASS({ip}:{port})");
                }
                else
                {
                    Console.WriteLine($" > [{connId},OnAccept] -> Server_GetClientAddress() Error");
                }

                long uid =Util.GetUserID();
                // 设置附加数据
                User user = new User(uid,connId);
                Session session = new Session();
                session.ConnId = connId;
                session.IpAddress = ip;
                session.Port = port;
                session.player = user;

                ///分配房间
                Room room=RoomManager.Instanse.AutoAlloc(user);

                ///进入房间
                PackageEnterRoom pack = new PackageEnterRoom(BingoClientModel.EnumPackCommand.GG_EnterRoom);
                WorkObject obj = new WorkObject();
                obj.pack = pack;
                obj.session = session;
                obj.room = room;
                RoomManager.Instanse.PushPackage(obj);


                ///设置连接用户数据
                if (Server.SetExtra(connId, session) == false)
                {
                    Console.WriteLine($" > [{connId},OnAccept] -> SetConnectionExtra fail");
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine("BingoTcpPackServer.Start() 异常");
                LogHelper.WriteFatal( ex);
            }

            return HandleResult.Ok;
        }
        /// <summary>
		/// 数据到达事件
		/// </summary>
		/// <param name="connId"></param>
		/// <param name="bytes"></param>
		/// <returns></returns>
		HandleResult OnReceive(IntPtr connId, byte[] bytes)
        {
            // 数据到达了
            try
            {
                // 获取附加数据
                var session = Server.GetExtra<Session>(connId);
                if (session != null)
                {
                    // clientInfo 就是accept里传入的附加数据了
                    Console.WriteLine($" > [{session.ConnId},OnReceive] ->  ({bytes.Length} bytes)");
                }
                else
                {
                    Console.WriteLine($" > [{connId},OnReceive] -> ({bytes.Length} bytes)");
                }
                
                int id = NetFunction.ntoh(BitConverter.ToInt32(bytes, 0));
                Package pack = PackageFactory.Instance.NewPackage((short)id, bytes);
                if(pack==null)
                {
                    Console.WriteLine($"实例化package {id} 失败");
                    return HandleResult.Ok;
                }

                User user = (User)session.player;
                //pack.Excute(pack, session);

                WorkObject obj = new WorkObject();
                obj.pack = pack;
                obj.session = session;
                obj.room = RoomManager.Instanse.GetRoom((int)user.GetRoomId());
                RoomManager.Instanse.PushPackage(obj);

                return HandleResult.Ok;
            }
            catch (Exception)
            {
                return HandleResult.Error;
            }
        }
        /// <summary>
		/// 连接关闭事件
		/// </summary>
		/// <param name="connId"></param>
		/// <param name="enOperation"></param>
		/// <param name="errorCode"></param>
		/// <returns></returns>
		HandleResult OnClose(IntPtr connId, SocketOperation enOperation, int errorCode)
        {
            if (errorCode == 0)
                Console.WriteLine($" > [{connId},OnClose]");
            else
                Console.WriteLine($" > [{connId},OnError] -> OP:{enOperation},CODE:{errorCode}");
            // return HPSocketSdk.HandleResult.Ok;

            //if (Server.RemoveExtra(connId) == false)
            //{
            //	Console.WriteLine(" > [{0},OnClose] -> SetConnectionExtra({0}, null) fail", connId);
            //}

            //ConsoleExt.ConsoleWlMethod(System.Reflection.MethodBase.GetCurrentMethod());

            var session = Server.GetExtra<Session>(connId);

            User user = (User)session.player;
            long rid = user.GetRoomId();
            if (rid >= 0)
            {///离开房间
                PackageLeavaRoom pack = new PackageLeavaRoom(BingoClientModel.EnumPackCommand.GG_LeaveRoom);
                WorkObject obj = new WorkObject();
                obj.session = session;
                obj.room = RoomManager.Instanse.GetRoom(rid);
                obj.pack = pack;
                RoomManager.Instanse.PushPackage(obj);
            }
            return HandleResult.Ok;
        }


        /// <summary>
        /// 服务器关闭事件
        /// </summary>
        /// <returns></returns>
        HandleResult OnShutdown()
        {
            // 服务关闭了
            Console.WriteLine("OnShutdown");
            return HandleResult.Ok;
        }

        public static void SendPackage(IntPtr conid, Package pack)
        {
            byte[] bytes=pack.GetBuffer();
            GameTcpServer.Instance.Server.Send(conid, bytes,bytes.Length);
        }
    }
}
